package cn.itcast.poi.utils.export;

import cn.itcast.poi.annotation.ExcelAttribute;
import lombok.Getter;
import lombok.Setter;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 导出Excel工具类
 * 基于模板打印的方式导出：
 *
 * @author zhang
 */
@Getter
@Setter
public class ExcelWithTemplateExportUtil<T> {

    /**
     * 写入数据的起始行
     */
    private int rowIndex;

    /**
     * 需要提取的样式所在的行号
     */
    private int styleIndex;

    /**
     * 对象的字节码
     */
    private Class<?> clazz;

    /**
     * 对象中的所有属性
     */
    private Field[] fields;

    public ExcelWithTemplateExportUtil(Class<?> clazz, int rowIndex, int styleIndex) {
        this.clazz = clazz;
        this.rowIndex = rowIndex;
        this.styleIndex = styleIndex;
        fields = clazz.getDeclaredFields();
    }

    public ExcelWithTemplateExportUtil() {
    }

    /**
     * 基于注解导出:直接将数据流返回前端
     * 参数：
     * response：
     * InputStream:模板的输入流
     * objs：数据
     * fileName：生成的文件名
     * flag: 是否生成序号
     */
    public void export(HttpServletResponse response, InputStream is, List<T> objs, String fileName,boolean flag) {

        XSSFWorkbook workbook = null;
        try {
            workbook = this.excelWrite(is, objs,flag);
            response = this.setResponseHeaders(response, fileName);
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (workbook != null) {
                    workbook.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 基于注解导出:直接将数据流写入到本地文件中,然后将本地文件上传至fastdfs,再将url返回给前端,由前端引导用户下载
     *
     * @param is         模板输入流
     * @param objs       具体数据集合
     * @param targetFile 目标本地文件对象
     * @param flag 是否生成序号
     * @throws Exception Exception
     */
    public void exportToLocalFile(InputStream is, List<T> objs, File targetFile,boolean flag) {
        XSSFWorkbook workbook = null;
        FileOutputStream fileOutputStream = null;
        try {
            workbook = this.excelWrite(is, objs,flag);
            fileOutputStream = new FileOutputStream(targetFile);
            workbook.write(fileOutputStream);
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (workbook != null) {
                    workbook.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 写数据
     * @param is 模板的输入流
     * @param objs 查询出来的数据
     * @param flag 是否生成序号
     * @return XSSFWorkbook
     * @throws Exception
     */
    private XSSFWorkbook excelWrite(InputStream is, List<T> objs,boolean flag) throws Exception {
        //1.根据模板创建工作簿
        XSSFWorkbook workbook = new XSSFWorkbook(is);
        //2.读取工作表
        Sheet sheet = workbook.getSheetAt(0);
        //3.提取公共的样式
        CellStyle[] styles = getTemplateStyles(sheet.getRow(styleIndex));
        //4.根据数据创建每一行和每一个单元格的数据2
        AtomicInteger datasAi = new AtomicInteger(rowIndex);
        for (T t : objs) {
            int andIncrement = datasAi.getAndIncrement();
            Row row = sheet.createRow(andIncrement);
            for (int i = 0; i < styles.length; i++) {
                Cell cell = row.createCell(i);
                cell.setCellStyle(styles[i]);
                for (Field field : fields) {
                    if (field.isAnnotationPresent(ExcelAttribute.class)) {
                        field.setAccessible(true);
                        ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);
                        if (i == ea.sort()) {
                            if (field.get(t) != null) {
                                cell.setCellValue(field.get(t).toString());
                            }
                        }
                       if(flag){
                           if (i == 0) {
                               cell.setCellValue(String.valueOf(andIncrement - 1));
                           }
                       }
                    }
                }
            }
        }
        return workbook;
    }


    public CellStyle[] getTemplateStyles(Row row) {
        CellStyle[] styles = new CellStyle[row.getLastCellNum()];
        for (int i = 0; i < row.getLastCellNum(); i++) {
            styles[i] = row.getCell(i).getCellStyle();
        }
        return styles;
    }

    /**
     * 设置response响应头
     *
     * @param response response
     * @param fileName 文件名
     * @return HttpServletResponse
     * @throws Exception Exception
     */
    public HttpServletResponse setResponseHeaders(HttpServletResponse response, String fileName) throws Exception {
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setContentType("application/octet-stream");
        response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes("ISO8859-1")));
        response.setHeader("filename", fileName);
        return response;
    }
}
